
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <cmath>

#include <lurpc/core/rpc_core.h>


namespace cli {

struct MyRecord {
    int32_t x = 0;
    int32_t y = 0;
    float_t z = 0.0;

    std::string name;

    std::vector<std::string> cs;

    MyRecord() = default;

    MyRecord(int32_t _x, int32_t _y, float_t _z, std::string _n, std::vector<std::string> _c)
            : x(_x), y(_y), z(_z), name(std::move(_n)), cs(std::move(_c)) {}

    template<typename Arch>
    void serialize(Arch &_arch) {
        _arch(x, y, z, name, cs);
    }
};

struct MyData {
    int id = 0;
    std::unordered_map<int, MyRecord> ds;

    template<typename Arch>
    void serialize(Arch &_arch) {
        _arch(id, ds);
    }
};

}


namespace cli {

MyData
call_service_132
(MyData& myData)
{
    return lurpc::rpc_call<MyData, MyData>(132, myData);
}

MyData
call_service_133
(MyRecord& _in1, MyData& _in2)
{
    return lurpc::rpc_call<MyData, MyRecord, MyData>(133, _in1, _in2);
}

int
call_service_134
(int a, int b)
{
    return lurpc::rpc_call<int, int, int>(134, a, b);
}

}

void initial_cli() {
    lurpc::rpc_services::load_from_file("../config/services");
}

void test_service_132() {
    std::cout << "********************** TEST 132 *******************************" << std::endl;
    // ================== prepare data ======================
    cli::MyData data {
            99,
            {
                    { 12, { 1, 2, 3, "Tom Cris", { "dsdsds", "212121", "cxcxcx" } } },
                    { 13, { 4, 5, 6, "Alex Mullen", { "545454", "gfgfgf", "l;" } } },
                    { 20, { 7, 8, 9, "Mark Alen", { "gf" } } }
            }
    };

    // ================== show data ======================
    std::cout << data.id << std::endl;
    for (auto& [k, v] : data.ds) {
        std::cout << k << ": " << v.x << ' ' << v.y << ' ' << v.z << v.name << ' ';
        for (auto& c : v.cs) std::cout << c << ' ';
        std::cout << std::endl;
    }
    std::cout << std::endl;

    // ================== call remote process ======================
    cli::MyData md = cli::call_service_132(data);

    // ================== show results ======================
    std::cout << md.id << std::endl;
    for (auto& [k, v] : md.ds) {
        std::cout << k << ": " << v.x << ' ' << v.y << ' ' << v.z << v.name << ' ';
        for (auto& c : v.cs) std::cout << c << ' ';
        std::cout << std::endl;
    }
    std::cout << std::endl;
}

void test_service_133() {
    std::cout << "********************** TEST 133 *******************************" << std::endl;
    // ================== prepare data ======================
    cli::MyData data {
            99,
            {
                    { 12, { 1, 2, 3, "Tom Cris", { "dsdsds", "212121", "cxcxcx" } } },
                    { 13, { 4, 5, 6, "Alex Mullen", { "545454", "gfgfgf", "l;" } } },
                    { 20, { 7, 8, 9, "Mark Alen", { "gf" } } }
            }
    };

    cli::MyRecord mr { 10, 9, 8, "Hahaha", { "nishuihan", "csgo", "jianwang3" } };

    // ================== show data ======================
    std::cout << data.id << std::endl;
    for (auto& [k, v] : data.ds) {
        std::cout << k << ": " << v.x << ' ' << v.y << ' ' << v.z << v.name << ' ';
        for (auto& c : v.cs) std::cout << c << ' ';
        std::cout << std::endl;
    }
    std::cout << std::endl;

    // ================== call remote process ======================
    cli::MyData md = cli::call_service_133(mr, data);

    // ================== show results ======================
    std::cout << md.id << std::endl;
    for (auto& [k, v] : md.ds) {
        std::cout << k << ": " << v.x << ' ' << v.y << ' ' << v.z << v.name << ' ';
        for (auto& c : v.cs) std::cout << c << ' ';
        std::cout << std::endl;
    }
    std::cout << std::endl;
}

void test_service_134() {
    std::cout << "********************** TEST 134 *******************************" << std::endl;
    int a = 3, b = 7;
    int ans = cli::call_service_134(a, b);
    std::cout << ans << std::endl;
}

int main(int argc, char** argv) {

    // ================== initial service info ======================
    initial_cli();

    test_service_132();
    test_service_133();
    test_service_134();

    return 0;
}